package com.jrauto.CarAppBackend.service.impl;

/**
 * @author : huiMing
 * Date : 2025年09月05日 10:39
 * @version V1.0
 */

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.time.Instant;
import java.util.concurrent.atomic.AtomicReference;

/**
 * AccessToken 服务，负责获取和刷新微信 access_token。
 * 获取小程序全局唯一后台接口调用凭据，token有效期为7200s,业务调用时会检测是否过期，过期则自动刷新。
 */

@Service
public class AccessTokenService {

    @Value("${wechat.appid}")
    private String appid;

    @Value("${wechat.secret}")
    private String secret;

    private final RestTemplate restTemplate = new RestTemplate();

    // 使用 AtomicReference 保证线程安全地存储 token
    private final AtomicReference<String> accessTokenRef = new AtomicReference<>();

    // 存储 token 的过期时间戳
    private volatile long expireTime = 0;

    /**
     * 获取 access_token。
     * 如果缓存中没有，或者已经过期，则触发刷新。
     * @return 有效的 access_token
     */
    public String getAccessToken() {
        // 1. 检查当前 token 是否已过期或为空
        if (accessTokenRef.get() == null || Instant.now().getEpochSecond() >= expireTime) {
            // 2. 如果过期，使用 synchronized 关键字确保只有一个线程去请求新 token
            synchronized (this) {
                // 双重检查锁定（Double-Checked Locking）
                // 再次检查是否已过期，防止多个线程进入 synchronized 块
                if (accessTokenRef.get() == null || Instant.now().getEpochSecond() >= expireTime) {
                    System.out.println("Access token expired or empty, triggering refresh...");
                    refreshAccessToken();
                }
            }
        }
        return accessTokenRef.get();
    }

    /**
     * 同步请求微信 API，刷新 access_token
     */
    private void refreshAccessToken() {
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}";

        try {
            String result = restTemplate.getForObject(url, String.class, appid, secret);
            JSONObject jsonObject = JSON.parseObject(result);
            String token = jsonObject.getString("access_token");
            Integer expiresIn = jsonObject.getInteger("expires_in");

            if (token != null && expiresIn != null) {
                // 更新 access_token 和过期时间
                accessTokenRef.set(token);
                // 设置过期时间，提前 5 分钟失效，以应对网络延迟或时间误差
                expireTime = Instant.now().getEpochSecond() + expiresIn - 180;
                System.out.println("Access token refreshed successfully.");
            } else {
                System.err.println("Failed to get access token: " + jsonObject.getString("errmsg"));
            }
        } catch (Exception e) {
            System.err.println("Error while refreshing access token: " + e.getMessage());
        }
    }
}
